#ifndef LSM6DSO_REGS_H
#define LSM6DSO_REGS_H

#include "driver/i2c_master.h"
#include <stdint.h>
#include <stddef.h>
#include <math.h>

/* LSM6DSO I2C Slave Address 7 Bit Format {SA0->GND ADD=6A SA0->VDDIO ADD=6B}*/
#define LSM6DSO_I2C_ADD_L 0x6A
#define LSM6DSO_I2C_ADD_H 0x6B

/* Device Identification (Who am I) */
#define LSM6DSO_ID       0x6C

/* Register map start */
#define LSM6DSO_FUNC_CFG_ACCESS              0x01U

#define LSM6DSO_PIN_CTRL                     0x02U

#define LSM6DSO_FIFO_CTRL1                   0x07U
#define LSM6DSO_FIFO_CTRL2                   0x08U
#define LSM6DSO_FIFO_CTRL3                   0x09U
#define LSM6DSO_FIFO_CTRL4                   0x0AU

#define LSM6DSO_COUNTER_BDR_REG1             0x0BU
#define LSM6DSO_COUNTER_BDR_REG2             0x0CU

#define LSM6DSO_INT1_CTRL                    0x0DU
#define LSM6DSO_INT2_CTRL                    0x0EU

#define LSM6DSO_WHO_AM_I                     0x0FU

#define LSM6DSO_CTRL1_XL                     0x10U
typedef enum{
    ODR_XL_OFF     = (0<<4),
    ODR_XL_1Hz6    = (11<<4),//also 12.5Hz in High Perfomance Mode(XL_HM_MODE = 0)
    ODR_XL_12Hz5   = (1<<4),
    ODR_XL_26Hz    = (2<<4),
    ODR_XL_52Hz    = (3<<4),
    ODR_XL_104Hz   = (4<<4),
    ODR_XL_208Hz   = (5<<4),
    ODR_XL_416Hz   = (6<<4),
    ODR_XL_833Hz   = (7<<4),
    ODR_XL_1k66Hz  = (8<<4),
    ODR_XL_3k33Hz  = (9<<4),
    ODR_XL_6k66Hz  = (10<<4),
} lsm6dso_odr_xl_t;//bits[7:4]
typedef enum{
    FS_XL_2g       = (0<<2),
    FS_XL_4g       = (2<<2),
    FS_XL_8g       = (3<<2),
    FS_XL_16g      = (1<<2),
} lsm6dso_fs_xl_t;//bits[3:2]
#define ACC_LSB_2G_PER                       0.061
#define ACC_LSB_4G_PER                       0.122
#define ACC_LSB_8G_PER                       0.244
#define ACC_LSB_16G_PER                      0.488

#define LSM6DSO_CTRL2_G                      0x11U
typedef enum{
    ODR_G_OFF      = (0<<4),
    ODR_G_12Hz5    = (1<<4),
    ODR_G_26Hz     = (2<<4),
    ODR_G_52Hz     = (3<<4),
    ODR_G_104Hz    = (4<<4),
    ODR_G_208Hz    = (5<<4),
    ODR_G_416Hz    = (6<<4),
    ODR_G_833Hz    = (7<<4),
    ODR_G_1k66Hz   = (8<<4),
    ODR_G_3k33Hz   = (9<<4),
    ODR_G_6k66Hz   = (10<<4),
} lsm6dso_odr_g_t;//bits[7:4]
typedef enum{
    FS_G_250dps    = (0<<2),
    FS_G_500dps    = (1<<2),
    FS_G_1000dps   = (2<<2),
    FS_G_2000dps   = (3<<2),
} lsm6dso_fs_g_t;//bits[3:2]
#define GYR_LSB_250_PER                      8.75
#define GYR_LSB_500_PER                      17.50
#define GYR_LSB_1000_PER                     35.0
#define GYR_LSB_2000_PER                     70.0

#define LSM6DSO_CTRL3_C                      0x12U
#define LSM6DSO_CTRL4_C                      0x13U
#define LSM6DSO_CTRL5_C                      0x14U
#define LSM6DSO_CTRL6_C                      0x15U
#define LSM6DSO_CTRL7_G                      0x16U
#define LSM6DSO_CTRL8_XL                     0x17U
#define LSM6DSO_CTRL9_XL                     0x18U
#define LSM6DSO_CTRL10_C                     0x19U
#define LSM6DSO_ALL_INT_SRC                  0x1AU
#define LSM6DSO_WAKE_UP_SRC                  0x1BU
#define LSM6DSO_TAP_SRC                      0x1CU
#define LSM6DSO_D6D_SRC                      0x1DU
#define LSM6DSO_STATUS_REG                   0x1EU
    #define TEM_DATA_AVAILABLE   (1<<2)
	#define GYR_DATA_AVAILABLE   (1<<1)
	#define ACC_DATA_AVAILABLE   (1<<0)
    
#define LSM6DSO_STATUS_SPIAUX                0x1EU

#define LSM6DSO_OUT_TEMP_L                   0x20U
#define LSM6DSO_OUT_TEMP_H                   0x21U

#define LSM6DSO_OUTX_L_G                     0x22U
#define LSM6DSO_OUTX_H_G                     0x23U
#define LSM6DSO_OUTY_L_G                     0x24U
#define LSM6DSO_OUTY_H_G                     0x25U
#define LSM6DSO_OUTZ_L_G                     0x26U
#define LSM6DSO_OUTZ_H_G                     0x27U
#define LSM6DSO_OUTX_L_A                     0x28U
#define LSM6DSO_OUTX_H_A                     0x29U
#define LSM6DSO_OUTY_L_A                     0x2AU
#define LSM6DSO_OUTY_H_A                     0x2BU
#define LSM6DSO_OUTZ_L_A                     0x2CU
#define LSM6DSO_OUTZ_H_A                     0x2DU

#define LSM6DSO_EMB_FUNC_STATUS_MAINPAGE     0x35U
#define LSM6DSO_FSM_STATUS_A_MAINPAGE        0x36U
#define LSM6DSO_FSM_STATUS_B_MAINPAGE        0x37U

#define LSM6DSO_STATUS_MASTER_MAINPAGE       0x39U
#define LSM6DSO_FIFO_STATUS1                 0x3AU
#define LSM6DSO_FIFO_STATUS2                 0x3BU

#define LSM6DSO_TIMESTAMP0                   0x40U
#define LSM6DSO_TIMESTAMP1                   0x41U
#define LSM6DSO_TIMESTAMP2                   0x42U
#define LSM6DSO_TIMESTAMP3                   0x43U

#define LSM6DSO_TAP_CFG0                     0x56U
#define LSM6DSO_TAP_CFG1                     0x57U
#define LSM6DSO_TAP_CFG2                     0x58U
#define LSM6DSO_TAP_THS_6D                   0x59U
#define LSM6DSO_INT_DUR2                     0x5AU
#define LSM6DSO_WAKE_UP_THS                  0x5BU
#define LSM6DSO_WAKE_UP_DUR                  0x5CU
#define LSM6DSO_FREE_FALL                    0x5DU
#define LSM6DSO_MD1_CFG                      0x5EU
#define LSM6DSO_MD2_CFG                      0x5FU

#define LSM6DSO_I3C_BUS_AVB                  0x62U
#define LSM6DSO_INTERNAL_FREQ_FINE           0x63U

#define LSM6DSO_INT_OIS                      0x6FU
#define LSM6DSO_CTRL1_OIS                    0x70U
#define LSM6DSO_CTRL2_OIS                    0x71U
#define LSM6DSO_CTRL3_OIS                    0x72U

#define LSM6DSO_X_OFS_USR                    0x73U
#define LSM6DSO_Y_OFS_USR                    0x74U
#define LSM6DSO_Z_OFS_USR                    0x75U

#define LSM6DSO_FIFO_DATA_OUT_TAG            0x78U

#define LSM6DSO_FIFO_DATA_OUT_X_L            0x79U
#define LSM6DSO_FIFO_DATA_OUT_X_H            0x7AU
#define LSM6DSO_FIFO_DATA_OUT_Y_L            0x7BU
#define LSM6DSO_FIFO_DATA_OUT_Y_H            0x7CU
#define LSM6DSO_FIFO_DATA_OUT_Z_L            0x7DU
#define LSM6DSO_FIFO_DATA_OUT_Z_H            0x7EU
/* Register map end */

/* Embedded functions register map start */
/* Before you access embedded functions reg, FUNC_CFG_ACCESS(01h)'s FUNC_CFG_EN bit need to be setted to 1 */
#define LSM6DSO_PAGE_SEL                     0x02U
#define LSM6DSO_EMB_FUNC_EN_A                0x04U
#define LSM6DSO_EMB_FUNC_EN_B                0x05U
#define LSM6DSO_PAGE_ADDRESS                 0x08U
#define LSM6DSO_PAGE_VALUE                   0x09U
#define LSM6DSO_EMB_FUNC_INT1                0x0AU
#define LSM6DSO_FSM_INT1_A                   0x0BU
#define LSM6DSO_FSM_INT1_B                   0x0CU
#define LSM6DSO_EMB_FUNC_INT2                0x0EU
#define LSM6DSO_FSM_INT2_A                   0x0FU
#define LSM6DSO_FSM_INT2_B                   0x10U
#define LSM6DSO_EMB_FUNC_STATUS              0x12U
#define LSM6DSO_FSM_STATUS_A                 0x13U
#define LSM6DSO_FSM_STATUS_B                 0x14U
#define LSM6DSO_PAGE_RW                      0x17U

#define LSM6DSO_EMB_FUNC_FIFO_CFG            0x44U
#define LSM6DSO_FSM_ENABLE_A                 0x46U
#define LSM6DSO_FSM_ENABLE_B                 0x47U
#define LSM6DSO_FSM_LONG_COUNTER_L           0x48U
#define LSM6DSO_FSM_LONG_COUNTER_H           0x49U
#define LSM6DSO_FSM_LONG_COUNTER_CLEAR       0x4AU
#define LSM6DSO_FSM_OUTS1                    0x4CU
#define LSM6DSO_FSM_OUTS2                    0x4DU
#define LSM6DSO_FSM_OUTS3                    0x4EU
#define LSM6DSO_FSM_OUTS4                    0x4FU
#define LSM6DSO_FSM_OUTS5                    0x50U
#define LSM6DSO_FSM_OUTS6                    0x51U
#define LSM6DSO_FSM_OUTS7                    0x52U
#define LSM6DSO_FSM_OUTS8                    0x53U
#define LSM6DSO_FSM_OUTS9                    0x54U
#define LSM6DSO_FSM_OUTS10                   0x55U
#define LSM6DSO_FSM_OUTS11                   0x56U
#define LSM6DSO_FSM_OUTS12                   0x57U
#define LSM6DSO_FSM_OUTS13                   0x58U
#define LSM6DSO_FSM_OUTS14                   0x59U
#define LSM6DSO_FSM_OUTS15                   0x5AU
#define LSM6DSO_FSM_OUTS16                   0x5BU

#define LSM6DSO_EMB_FUNC_ODR_CFG_B           0x5FU
#define LSM6DSO_STEP_COUNTER_L               0x62U
#define LSM6DSO_STEP_COUNTER_H               0x63U
#define LSM6DSO_EMB_FUNC_SRC                 0x64U
#define LSM6DSO_EMB_FUNC_INIT_A              0x66U
#define LSM6DSO_EMB_FUNC_INIT_B              0x67U
/* Embedded functions register map end */

esp_err_t lsm6dso_read_reg(const i2c_master_dev_handle_t lsm6dso_handle, uint8_t *reg, uint8_t *data, uint16_t len);
esp_err_t lsm6dso_write_reg(const i2c_master_dev_handle_t lsm6dso_handle, uint8_t *reg, uint8_t *data);

#endif /*LSM6DSO_DRIVER_H */